package base.thread_demo.demo07;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 单线程实现交替输出0,1很简单(直接在任务方法中用一个flag变量控制即可)，怎样通过多线程交替输出0,1呢？
 * 还需要注意的是，0,1交替说明至少有个判断标志是多个线程能够共享的，此案例中用的是一个static flag标志控制.
 *
 * 如果想让t1专职负责输出0,t2专职负责输出1 该如何做?(详见类 UnionRunnable上注解)
 */
public class ToggleOutputDemo {
    private static final Logger log = LoggerFactory.getLogger(ToggleOutputDemo.class);

    public static void main(String[] args) {
//      test1();
      test2();
    }

    public static void test2(){
        MyLock2 lock = new MyLock2(true);

        UnionRunnable2 r1 = new UnionRunnable2(lock);
        UnionRunnable2 r2 = new UnionRunnable2(lock);

        new Thread(r1, "t1").start();
        new Thread(r2, "t2").start();
    }

    public static void test1(){
        MyLock lock = new MyLock();

        UnionRunnable r1 = new UnionRunnable(lock);
        UnionRunnable r2 = new UnionRunnable(lock);

        new Thread(r1, "t1").start();
        new Thread(r2, "t2").start();
    }
}

/**
 * 如果想让t1专职负责输出0,t2专职负责输出1,那么需要两个线程任务,即两个Runnable接口实现,然后将UnionRunnable中的if...else
 * 拆分开,if内部逻辑放到一个线程任务中,else内部逻辑放到另一个线程任务中,拆分开的两个线程任务中还是根据flag来判断,是否轮
 * 到输出0或者1的逻辑.这样就可以使用wait和notifyAll了
 */
class UnionRunnable implements Runnable{
    private static final Logger log = LoggerFactory.getLogger(UnionRunnable.class);
    public MyLock lock;
    private static boolean flag = true;

    /**让两个不同UnionRunnable对象持有同一把锁对象*/
    public UnionRunnable(MyLock lock){
        this.lock = lock;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (lock) {
                // 变量 flag 设置为static，确保flag属于UnionRunnable类变量，这样线程就能确保把0和1交替输出
                // 分析：t1输出了0 ->false，切换到t2,t2发现static的flag，t2只能执行else语句。
                if (flag) {
                    log.info("{} -> 000000000000", Thread.currentThread().getName());
                    flag = false;
                } else {
                    log.info("{} -> 1", Thread.currentThread().getName());
                    flag = true;
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class MyLock{}

class MyLock2{
    private boolean flag;
    public MyLock2(boolean flag){
        this.flag = flag;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

class UnionRunnable2 implements Runnable {
    private static final Logger log = LoggerFactory.getLogger(UnionRunnable2.class);
    private MyLock2 lock;
    public UnionRunnable2(MyLock2 lock){
        this.lock = lock;
    }
    @Override
    public void run() {
        while (true){
            synchronized (lock){// 拿到lock锁后，执行任务完毕并改变锁上标记flag.
                if(lock.isFlag()){
                    log.info("{} -> 000000000", Thread.currentThread().getName());
                    lock.setFlag(false);
                }else{
                    log.info("{} ->1", Thread.currentThread().getName());
                    lock.setFlag(true);
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
